///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IMAGE_VERTEX_CBSPLINE_H_
#define _BUOLA_IMAGE_VERTEX_CBSPLINE_H_

#include <buola/image.h>
#include <buola/iterator/range.h>

namespace buola { namespace img {

class CBSpline
{
    struct SPoint
    {
        double mX;
        double mY;
        double mA;
    };
    
public:
    CBSpline()=default;
    CBSpline(const CBSpline&)=default;
    CBSpline(CBSpline&&)=default;

    template<typename tRange>
    explicit CBSpline(tRange &&pPoints)
    {
        Init(std::forward<tRange>(pPoints));
    }

    CBSpline(const CPoint_d &p1,const CPoint_d &p2,const CPoint_d &p3,const CPoint_d &p4)
    {
        Init(p1,p2,p3,p4);
    }

    template<typename tRange>
    void Init(const tRange &pPoints)
    {
        mPoints.resize(range_size(pPoints));

        int i=0;
        
        for(const CPoint_d &p : pPoints)
        {
            mPoints[i].mX=p.x;
            mPoints[i].mY=p.y;
            i++;
        }

        Prepare();
    }

    void Init(const CPoint_d &p1,const CPoint_d &p2,const CPoint_d &p3,const CPoint_d &p4)
    {
        mPoints.resize(4);

        mPoints[0].mX=p1.x;
        mPoints[0].mY=p1.y;
        mPoints[1].mX=p2.x;
        mPoints[1].mY=p2.y;
        mPoints[2].mX=p3.x;
        mPoints[2].mY=p3.y;
        mPoints[3].mX=p4.x;
        mPoints[3].mY=p4.y;

        Prepare();
    }
    
    double Get(double x) const;
    double GetNext(double x) const;

private:
    void Prepare();
    ///find the knot immediately before \p pX, searching between i and j (inclusive)
    int BSearch(double pX,int i,int j) const;
    double Interpolation(double pX,int i) const;
    double ExtrapolationLeft(double x) const;
    double ExtrapolationRight(double x) const;

private:
    std::vector<SPoint> mPoints;
    mutable int mLastI;
};

/*namespace img*/ } /*namespace buola*/ }

#endif
